﻿using System;
using System.Windows.Media.Imaging;
using AccessControl.Wpf.ViewModels;
using AccessControl.Contracts.Models;
using System.Windows.Media;
using AccessControl.Contracts.Video;
using AccessControl.Gateway.Managers;
using System.Windows;
using System.Windows.Threading;
using FFMpegDecoder;
using System.IO;

namespace AccessControl.Wpf.Entries.ViewModels
{
	class CameraViewModel : ViewModel
	{
		#region Fields

		int _pitch;
		ICamera _Camera;
		byte[] _imageBytes;
		Decoder _videoDecoder;
		IVideoPlayer _videoPlayer;
		ImageSource _currentFrame;
		int _imageWidth, _imageHeight;
		WriteableBitmap _currentBitmap;
		bool _IsStarting, _IsFailed;
		static readonly DispatcherSynchronizationContext _synchronizationContext = new DispatcherSynchronizationContext();
		
		#endregion

		#region Public Constructor

		public CameraViewModel(ICamera camera)
		{
			Camera = camera;
		}

		#endregion

		#region Public Properties

		public ICamera Camera
		{
			get { return _Camera; }
			set
			{
				if (_Camera != value)
				{
					_Camera = value;
					NotifyPropertyChanged("Camera");
				}
			}
		}

		public ImageSource CurrentFrame
		{
			get{ return _currentFrame; }
			set
			{
				_currentFrame = value;
				NotifyPropertyChanged("CurrentFrame");
			}
		}

		public bool IsStarting
		{
			get { return _IsStarting; }
			set
			{
				if (_IsStarting != value)
				{
					_IsStarting = value;
					NotifyPropertyChanged("IsStarting");
				}
			}
		}

		public bool IsFailed
		{
			get { return _IsFailed; }
			set
			{
				if (_IsFailed != value)
				{
					_IsFailed = value;
					NotifyPropertyChanged("IsFailed");
				}
			}
		}
		
		

		#endregion

		#region Public Members

		public void StartVideo()
		{
			lock (this)
			{
				/* Create the player */
				_videoPlayer = Session.Instance.CreateVideoPlayer();
				/* Register to the events */
				_videoPlayer.VideoStarted += (OnVideoStarted);
				_videoPlayer.NewFrame += (OnNewVideoFrame);
				if (_videoPlayer.RequestStartVideo(Camera.Ip, Camera.PortNumber))
					IsStarting = true;
			}
		}

		void OnVideoStarted(bool bSuccess)
		{
			_synchronizationContext.Post(delegate { IsStarting = false; }, null);
			_synchronizationContext.Post(delegate { IsFailed = !bSuccess; }, null);
		}

		public void StopVideo()
		{
			lock (this)
			{
				/* First of all */
				if (_videoPlayer == null)
					return;

				/* Unregister to the new frame event */
				_videoPlayer.NewFrame -= (OnNewVideoFrame);
				/* And stop */
				_videoPlayer.RequestStopVideo();
			}
		}


		void OnNewVideoFrame(byte[] frameBytes, DateTime timeStamp, int width, int height)
		{
			lock (this)
			{
				/* Init the decoder first */
				if (_videoDecoder == null)
				{
					_videoDecoder = new Decoder();
					if (!_videoDecoder.Initialize(width, height))
					{
						_videoDecoder = null;
						return;
					}
				}

				/* Create the image bytes if we need to */
				if (_imageBytes == null || _imageWidth != width || _imageHeight != height)
				{
					_imageBytes = new byte[width * height * 4];
					_imageWidth = width;
					_imageHeight = height;
				}

				/* Decode */
				if (_videoDecoder.Decode(frameBytes, _imageBytes, 0, 0, _imageWidth * 4, true))
				{
					/* Switch to update the image */
					_synchronizationContext.Post(delegate
					{
						try
						{
							WriteableBitmap bmp = new WriteableBitmap(_imageWidth, _imageHeight, 96, 96, PixelFormats.Bgr32, null);
							bmp.WritePixels(new Int32Rect(0, 0, _imageWidth, _imageHeight), _imageBytes, _imageWidth * 4, 0);
							CurrentFrame = bmp;
						}
						catch (Exception e)
						{
						}
					}, null);
				}
			}
		}

		void UpdateCurrentFrame(byte[] imageBytes)
		{

		}

		#endregion
	}
}
